package com.mybank.myaccounts.service.impl;

import com.mybank.common.entity.AccountApplication;
import com.mybank.common.entity.AccountType;
import com.mybank.common.entity.Customer;
import com.mybank.myaccounts.dto.AccountApplicationDto;
import com.mybank.myaccounts.exception.ResourceNotFoundException;
import com.mybank.myaccounts.mapper.AccountApplicationMapper;
import com.mybank.myaccounts.repository.AccountApplicationRepository;
import com.mybank.myaccounts.repository.AccountTypeRepository;
import com.mybank.myaccounts.service.AccountApplicationService;
import com.mybank.myaccounts.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class AccountApplicationServiceImpl implements AccountApplicationService {

    private final AccountApplicationRepository accountApplicationRepository;
    private final AccountTypeRepository accountTypeRepository;
    private final AccountApplicationMapper accountApplicationMapper;
    private final UserService userService;

    @Autowired
    public AccountApplicationServiceImpl(
            AccountApplicationRepository accountApplicationRepository,
            AccountTypeRepository accountTypeRepository,
            AccountApplicationMapper accountApplicationMapper,
            UserService userService) {
        this.accountApplicationRepository = accountApplicationRepository;
        this.accountTypeRepository = accountTypeRepository;
        this.accountApplicationMapper = accountApplicationMapper;
        this.userService = userService;
    }

    @Override
    @Transactional
    public AccountApplicationDto createApplication(Long userId, AccountApplicationDto applicationDto) {
        // Get customer from user ID
        Customer customer = userService.getCustomerByUserId(userId)
                .orElseThrow(() -> new ResourceNotFoundException("No customer found for user ID: " + userId));
        
        // Get account type
        AccountType accountType = accountTypeRepository.findById(applicationDto.getAccountTypeId())
                .orElseThrow(() -> new ResourceNotFoundException("Account type not found with ID: " + applicationDto.getAccountTypeId()));
        
        // Create application entity
        AccountApplication application = accountApplicationMapper.toEntity(applicationDto, customer, accountType);
        
        // Set default values if not provided
        if (application.getStatus() == null) {
            application.setStatus("Pending");
        }
        
        application.setApplicationDate(LocalDateTime.now());
        
        // Save application
        AccountApplication savedApplication = accountApplicationRepository.save(application);
        
        // Return DTO
        return accountApplicationMapper.toDto(savedApplication);
    }

    @Override
    @Transactional(readOnly = true)
    public Optional<AccountApplicationDto> getApplicationById(Long applicationId) {
        return accountApplicationRepository.findById(applicationId)
                .map(accountApplicationMapper::toDto);
    }

    @Override
    @Transactional(readOnly = true)
    public List<AccountApplicationDto> getApplicationsByUserId(Long userId) {
        // Get customer ID from user ID
        Long customerId = userService.getCustomerIdByUserId(userId)
                .orElseThrow(() -> new ResourceNotFoundException("No customer found for user ID: " + userId));
        
        // Get applications for this customer
        List<AccountApplication> applications = accountApplicationRepository.findByCustomerCustomerId(customerId);
        
        // Convert to DTOs
        return accountApplicationMapper.toDtoList(applications);
    }

    @Override
    @Transactional(readOnly = true)
    public List<AccountApplicationDto> getApplicationsByUserIdAndStatus(Long userId, String status) {
        // Get customer ID from user ID
        Long customerId = userService.getCustomerIdByUserId(userId)
                .orElseThrow(() -> new ResourceNotFoundException("No customer found for user ID: " + userId));
        
        // Get applications for this customer with the specified status
        List<AccountApplication> applications = accountApplicationRepository.findByCustomerCustomerIdAndStatus(customerId, status);
        
        // Convert to DTOs
        return accountApplicationMapper.toDtoList(applications);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<AccountApplicationDto> getAllApplications(Pageable pageable) {
        return accountApplicationRepository.findAll(pageable)
                .map(accountApplicationMapper::toDto);
    }

    @Override
    @Transactional
    public AccountApplicationDto updateApplicationStatus(Long applicationId, String status, String notes) {
        // Get application
        AccountApplication application = accountApplicationRepository.findById(applicationId)
                .orElseThrow(() -> new ResourceNotFoundException("Application not found with ID: " + applicationId));
        
        // Update status
        application.setStatus(status);
        
        // Update notes if provided
        if (notes != null && !notes.isEmpty()) {
            application.setNotes(notes);
        }
        
        // If status is "Approved", set approval date
        if ("Approved".equalsIgnoreCase(status)) {
            application.setApprovalDate(LocalDateTime.now());
        }
        
        // Save updated application
        AccountApplication updatedApplication = accountApplicationRepository.save(application);
        
        // Return DTO
        return accountApplicationMapper.toDto(updatedApplication);
    }
}